#include "lib.h"
#include <memory.h>

#include "vpguts.h"
#include "vphand.h"
#include "shue.h"
#include "vpsaved.h"
#include "cardmgr.h"
#include "vpconn.h"

#include "jbtr.h"
#include "jokp.h"
#include "wld2.h"
#include "ace8.h"
#include "amer.h"
#include "bonp.h"
#include "bpdx.h"
#include "dbnp.h"
#include "ddbp.h"
#include "ddjp.h"
#include "djpk.h"
#include "ldeu.h"
#include "wld7.h"
#include "bw2.h"
#include "pikm.h"
#include "mystery.h"
//
// The order here MUST match the SQL machId
//
#include "log.h"

#define NUMGUTS	(sizeof(sGuts) / sizeof(sGuts[0]))

static VPGuts* sGuts[] =
{
	new JacksOrBetterGame(VPGuts::LOW),
	new JacksOrBetterGame(VPGuts::MEDIUM),
	new JacksOrBetterGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new JokerPokerGame(VPGuts::LOW),
	new JokerPokerGame(VPGuts::MEDIUM),
	new JokerPokerGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new DeucesWildGame(VPGuts::LOW),
	new DeucesWildGame(VPGuts::MEDIUM),
	new DeucesWildGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new AcesOrEightsGame(VPGuts::LOW),
	new AcesOrEightsGame(VPGuts::MEDIUM),
	new AcesOrEightsGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new AllAmericanGame(VPGuts::LOW),
	new AllAmericanGame(VPGuts::MEDIUM),
	new AllAmericanGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new BonusPokerGame(VPGuts::LOW),
	new BonusPokerGame(VPGuts::MEDIUM),
	new BonusPokerGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new BonusPokerDeluxeGame(VPGuts::LOW),
	new BonusPokerDeluxeGame(VPGuts::MEDIUM),
	new BonusPokerDeluxeGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new DoubleBonusPokerGame(VPGuts::LOW),
	new DoubleBonusPokerGame(VPGuts::MEDIUM),
	new DoubleBonusPokerGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new DoubleDoubleBonusPokerGame(VPGuts::LOW),
	new DoubleDoubleBonusPokerGame(VPGuts::MEDIUM),
	new DoubleDoubleBonusPokerGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new DoubleDoubleJackpotPokerGame(VPGuts::LOW),
	new DoubleDoubleJackpotPokerGame(VPGuts::MEDIUM),
	new DoubleDoubleJackpotPokerGame(VPGuts::HIGH),
	new DoubleDoubleJackpotPokerGame(VPGuts::CUSTOM),	// CSN-6225

	new DoubleJackpotPokerGame(VPGuts::LOW),
	new DoubleJackpotPokerGame(VPGuts::MEDIUM),
	new DoubleJackpotPokerGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new LooseDeucesGame(VPGuts::LOW),
	new LooseDeucesGame(VPGuts::MEDIUM),
	new LooseDeucesGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new SevensWildGame(VPGuts::LOW),
	new SevensWildGame(VPGuts::MEDIUM),
	new SevensWildGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new BonusDeucesWildGame(VPGuts::LOW),
	new BonusDeucesWildGame(VPGuts::MEDIUM),
	new BonusDeucesWildGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new PickEmPokerGame(VPGuts::LOW),
	new PickEmPokerGame(VPGuts::MEDIUM),
	new PickEmPokerGame(VPGuts::HIGH),
	NULL,	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker

	new MysteryGame(VPGuts::LOW),
	new MysteryGame(VPGuts::MEDIUM),
	new MysteryGame(VPGuts::HIGH),
	NULL	// CSN-6225: custom paytable only implemented for Double Double Jackpot Poker
};

VPGuts*
VPGuts::getGuts(int32 ID, int32 whichFreq)
{
	return (VPGuts*)(ID * NUMFREQS + whichFreq < NUMGUTS
		? sGuts[ID * NUMFREQS + whichFreq]
		: 0);
}

void
VPGuts::dealHand(Shue* shue, VPHand* hand)
{
#if (_DEBUG && DEBUGKNOWNHANDS)
	static uint8 handIndex=0;
	static uint8 handArray[][5] = 
	{
		{0x32,0x4d,0x18,0x2d,0x36},	// Pair
		{0x32,0x4d,0x12,0x2d,0x26},	// 2 pair
		{0x15,0x2c,0x35,0x25,0x39},	// 3 of a kind
		{0x24,0x15,0x46,0x37,0x28},	// Straight
		{0x22,0x2a,0x26,0x2d,0x27},	// Flush
		{0x25,0x2c,0x15,0x45,0x1c},	// Full House
		{0x22,0x2e,0x32,0x12,0x42},	// Four 2s
		{0x29,0x26,0x25,0x28,0x27},	// Straight Flush
		{0x4a,0x4b,0x4c,0x4d,0x4e},	// Seq Royal Flush
	};

	// Bounds check the index
	if (handIndex >= sizeof(handArray) / (sizeof(uint8) * 5))
		handIndex = 0;
 	// Add each card to the hand
	for (int32 i=0; i<5; ++i)
		hand->add(handArray[handIndex][i]);
	++handIndex;

#else
	hand->add(shue->getCard());
	hand->add(shue->getCard());
	hand->add(shue->getCard());
	hand->add(shue->getCard());
	hand->add(shue->getCard());
#endif
}

void
VPGuts::makeDealtHandForClient(VPHand* src, VPHand* dest)
{
	int32 i;

	for (i = 0; i < src->getCount(); i++)
		dest->add(src->getCardAt(i));
}

void
VPGuts::rollbackDeal(Shue* shue, VPHand* hand)
{
	shue->pushBackNCards(hand->getCount());
	hand->removeAll();
}

bool8
VPGuts::isHoldTheseValid(uint8 held)
{
	return (bool8)((held & ~0x1f) == 0);
}

void
VPGuts::drawHand(uint8 held, Shue* shue, VPHand* hand)
{
	int32 i;

	for (i = 0; i < 5; i++)
		if ((held & (1 << i)) == 0)
			hand->replace(i, shue->getCard());
}

void
VPGuts::makeDrawnHandForClient(VPHand* src, VPHand* dest)
{
	int32 i;

	for (i = 0; i < src->getCount(); i++)
		dest->add(src->getCardAt(i));
}

void
VPGuts::rollbackDraw(uint8 held, Shue* shue, VPHand* hand)
{
	int32 i, numDrawn;

	for (numDrawn = i = 0; i < 5; i++)
		if ((held & (1 << i)) == 0)
			++numDrawn;

	shue->pushBackNCards(numDrawn);
	rollbackDeal(shue, hand);
	dealHand(shue, hand);
}

int32
VPGuts::doubleUpCompare(uint8 dealer, uint8 player)
{
	int32 dRank, pRank;

	//
	// NOTE WELL:  This function only works on a standard 52-card deck
	//			   without jokers or wild cards.
	//

	dRank = getCardMgr()->getRank(dealer);
	pRank = getCardMgr()->getRank(player);

	return dRank - pRank;
}

void
VPGuts::restoreHand(Shue* shue, VPHand* hand, VPokerSavedGame* saved)
{
	hand->restore(saved->cards, VPokerSavedGame::MAXCARDS);
}

void 
VPGuts::createSubGameData(uint8* subGameData, int32* length, int32 maxlength) 
{
	*length = 0;
}

void VPGuts::restoreSubGameData(uint8* subGameData, int32* length)
{
}

uint8
VPGuts::restoreHeldCards(uint8* dealt, uint8* drawn, int32 num)
{
	uint8 result = 0;
	int32 i;

	for (i = 0; i < num; i++)
		if (dealt[i] == drawn[i])
			result |= (1 << i);

	return result;
}


//////////////////////////////////////////////////////////////////////////////
// CleaupGuts cleans sGuts[] to avoid false reports of memory leaks.
//////////////////////////////////////////////////////////////////////////////
static 
class CleanupGuts
{
public:
	~CleanupGuts()
	{
		for (int i = 0; i < NUMGUTS; ++i )
		{
			delete sGuts[i];
			sGuts[i] = 0;
		}
	}
} autoRunCleanupGutsOnExit;
